/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ImmersionConstants } from '../common/ImmersionConstants';

export interface Size {
  width: number;
  height: number;
}

export interface Position {
  x?: number;
  y?: number;
}

/**
 * 沉浸式计算规则
 */
interface AdaptiveImmersionRule {
  // 视频比例
  videoRatio: number;

  // 窗口宽度 (left≤x<right)
  windowWidthRange: number[];

  // 窗口比例范围 (left≤x<right)
  windowRatioRange: number[];

  // 沉浸计算规则
  immersionCalculationFunc: (videoSize: Size, windowSize: Size, bottomTabHeight: number, statusBarHeight: number) => ImmersionInfo;
}

/**
 * 当前屏幕及窗口信息
 * videoRatio: 视频比例
 * windowWidth: 窗口宽
 * windowRatio: 窗口宽高比
 */
export interface InputInfo {
  videoRatio: number;
  windowWidth: number;
  windowRatio: number;
}

/**
 * 沉浸状态
 * isStatusBarImmersive: 状态栏是否沉浸
 * isBottomTabImmersive: 底部tab栏是否沉浸
 */
export interface ImmersionSetting {
  isStatusBarImmersive: boolean;
  isBottomTabImmersive: boolean;
}

/**
 * 沉浸信息
 * videoSize: videoSize 尺寸
 * videoPositionOffset: video 相对于窗口左上角锚点的偏移量
 * immersionMode: 沉浸模式
 */
export interface ImmersionInfo {
  videoSize: Size;
  videoPosition: Position;
  immersionSetting: ImmersionSetting;
}

/**
 * 沉浸规则集
 */
export class ImmersionRuleSet {
  // 单例实例
  private static instance: ImmersionRuleSet;
  private readonly tag: string = ImmersionRuleSet.name;

  private constructor() {}

  // 获取单例实例的静态方法
  public static getInstance(): ImmersionRuleSet {
    if (!ImmersionRuleSet.instance) {
      ImmersionRuleSet.instance = new ImmersionRuleSet();
    }
    return ImmersionRuleSet.instance;
  }

  public getImmersionRules(): AdaptiveImmersionRule[] {
    return DEFAULT_IMMERSION_RULES;
  }

  // 获取单个数据集信息
  public getImmersionRule(inputInfo: InputInfo): AdaptiveImmersionRule | undefined {
    if (inputInfo) {
      return DEFAULT_IMMERSION_RULES.find((item: AdaptiveImmersionRule) => {
        return (
          item.videoRatio === inputInfo.videoRatio &&
          item.windowWidthRange[0] <= inputInfo.windowWidth &&
          inputInfo.windowWidth < item.windowWidthRange[1] &&
          item.windowRatioRange[0] <= inputInfo.windowRatio &&
          inputInfo.windowRatio < item.windowRatioRange[1]
        );
      });
    } else {
      console.error(this.tag, `InputInfo is null or undefined`);
      return undefined;
    }
  }
}

const DEFAULT_IMMERSION_RULES: AdaptiveImmersionRule[] = [
  /**
   * 1
   * rule: 视频比例：9/16、窗口宽：[0, Infinity]、窗口比例：[9 / 7.2, +∞)
   * func: "高度：窗口高 | 宽度：自适应 | 状态栏：沉浸 | 底部tab：沉浸"
   */
  {
    videoRatio: ImmersionConstants.VIDEO_ASPECT_RATIO_9_16,
    windowWidthRange: [0, Infinity],
    windowRatioRange: [ImmersionConstants.WINDOW_ASPECT_RATIO_9_7o2, Infinity],
    immersionCalculationFunc: (videoSize: Size, windowSize: Size, bottomTabHeight: number, statusBarHeight: number): ImmersionInfo => {
      return commonFullImmersionCalculationFunc(windowSize);
    },
  },
  /**
   * 2
   * rule: 视频比例：9/16、窗口宽：[0, Infinity]、窗口比例：[9 / 10.8, 9 / 7.2)
   * func: "高度：窗口高 | 宽度：自适应 | 状态栏：沉浸 | 底部tab：沉浸"
   */
  {
    videoRatio: ImmersionConstants.VIDEO_ASPECT_RATIO_9_16,
    windowWidthRange: [0, Infinity],
    windowRatioRange: [ImmersionConstants.WINDOW_ASPECT_RATIO_9_10o8, ImmersionConstants.WINDOW_ASPECT_RATIO_9_7o2],
    immersionCalculationFunc: (videoSize: Size, windowSize: Size, bottomTabHeight: number, statusBarHeight: number): ImmersionInfo => {
      return commonFullImmersionCalculationFunc(windowSize);
    },
  },
  /**
   * 3
   * rule: 视频比例：9/16、窗口宽：[0, Infinity]、窗口比例：[9 / 14.4, 9 / 10.8)
   * func: "高度：窗口高 | 宽度：自适应 | 状态栏：沉浸 | 底部tab：沉浸"
   */
  {
    videoRatio: ImmersionConstants.VIDEO_ASPECT_RATIO_9_16,
    windowWidthRange: [0, Infinity],
    windowRatioRange: [ImmersionConstants.WINDOW_ASPECT_RATIO_9_14o4, ImmersionConstants.WINDOW_ASPECT_RATIO_9_10o8],
    immersionCalculationFunc: (videoSize: Size, windowSize: Size, bottomTabHeight: number, statusBarHeight: number): ImmersionInfo => {
      return commonFullImmersionCalculationFunc(windowSize);
    },
  },
  /**
   * 4
   * rule: 视频比例：9/16、窗口宽：[0, Infinity]、窗口比例：[9 / 18, 9 / 14.4)
   * func:
   * 1. [9 / 16, 9 / 14.4), "高度：自适应（裁剪） | 宽度：窗口宽 | 状态栏：沉浸 | 底部tab：沉浸"
   * 2. [9 / 18, 9 / 16), "高度：窗口高 | 宽度：自适应（裁剪） | 状态栏：沉浸 | 底部tab：沉浸"
   */
  {
    videoRatio: ImmersionConstants.VIDEO_ASPECT_RATIO_9_16,
    windowWidthRange: [0, Infinity],
    windowRatioRange: [ImmersionConstants.WINDOW_ASPECT_RATIO_9_18, ImmersionConstants.WINDOW_ASPECT_RATIO_9_14o4],
    immersionCalculationFunc: (videoSize: Size, windowSize: Size, bottomTabHeight: number, statusBarHeight: number): ImmersionInfo => {
      const windowWidth = windowSize.width;
      const windowHeight = windowSize.height;
      if (ImmersionConstants.WINDOW_ASPECT_RATIO_9_16 <= windowWidth / windowHeight) {
        return {
          videoSize: {
            width: windowWidth,
            height: windowWidth / ImmersionConstants.WINDOW_ASPECT_RATIO_9_16,
          },
          videoPosition: {
            x: 0,
            y: -(windowWidth / ImmersionConstants.WINDOW_ASPECT_RATIO_9_16 - windowHeight) / 2,
          },
          immersionSetting: {
            isStatusBarImmersive: true,
            isBottomTabImmersive: true,
          },
        } as ImmersionInfo;
      } else {
        return {
          videoSize: {
            width: windowHeight * ImmersionConstants.WINDOW_ASPECT_RATIO_9_16,
            height: windowHeight,
          },
          videoPosition: {
            x: -(windowHeight * ImmersionConstants.WINDOW_ASPECT_RATIO_9_16 - windowWidth) / 2,
            y: 0,
          },
          immersionSetting: {
            isStatusBarImmersive: true,
            isBottomTabImmersive: true,
          },
        } as ImmersionInfo;
      }
    },
  },
  /**
   * 5
   * rule: 视频比例：9/16、窗口宽：[0, Infinity]、窗口比例：[9 / 20, 9 / 18)
   * func: "减去底部Tab高度后：
   1、若剩余区域大于等于9:16的视频，宽撑满，上下区域自适应裁剪
   2、若剩余区域小于9:16的视频，从窗口顶部开始计算，缩放视频到高度撑满，
   缩放大小最大为显示区域的9:17.8，若还有剩余高度，不做处理。左右自适应裁剪"
   */
  {
    videoRatio: ImmersionConstants.VIDEO_ASPECT_RATIO_9_16,
    windowWidthRange: [0, Infinity],
    windowRatioRange: [ImmersionConstants.WINDOW_ASPECT_RATIO_9_20, ImmersionConstants.WINDOW_ASPECT_RATIO_9_18],
    immersionCalculationFunc: (videoSize: Size, windowSize: Size, bottomTabHeight: number, statusBarHeight: number): ImmersionInfo => {
      const windowWidth = windowSize.width;
      const windowHeight = windowSize.height;
      const restShowAreaHeight = windowHeight - bottomTabHeight; // 剩余区域的高
      const restShowAreaWidth = windowWidth; // 剩余区域的宽
      const restShowAreaRatio = restShowAreaWidth / restShowAreaHeight; // 剩余区域比例
      let isStatusBarImmersive: boolean = true; // 这种沉浸式情况下 状态栏必定沉浸
      let isBottomTabImmersive: boolean = false;
      let videoWidth: number;
      let videoHeight: number;
      let X = 0;
      let Y = 0;

      if (restShowAreaRatio >= ImmersionConstants.WINDOW_ASPECT_RATIO_9_16) {
        // 如果剩余区域大于等于9:16的视频的高度
        videoWidth = windowWidth; // 宽撑满
        videoHeight = videoWidth / ImmersionConstants.WINDOW_ASPECT_RATIO_9_16; // 上下区域自适应裁剪
        Y = -(videoHeight - restShowAreaHeight) / 2;
        isBottomTabImmersive = Y < 0;
      } else if (9 / 17.8 <= restShowAreaRatio && restShowAreaRatio < ImmersionConstants.WINDOW_ASPECT_RATIO_9_16) {
        // 如果剩余区域小于9:16的视频，将视频最大缩放到9:17.8
        // 如果剩余区域的高度在16~17.8之间 ， 剩余高度撑满，宽自适应，导致需要左右裁剪, 下tab不需要沉浸
        videoHeight = restShowAreaHeight; // 高度撑满
        videoWidth = videoHeight * ImmersionConstants.WINDOW_ASPECT_RATIO_9_16; // 宽自适应
        X = -(videoWidth - windowWidth) / 2; //左右裁剪
      } else {
        // 如果剩余区域的高度比17.8还大， 最大将视频放大到9:17.8
        videoWidth = windowWidth * ImmersionConstants.VIDEO_STRETCH_ASPECT_RATIO_17o8_16;
        videoHeight = videoWidth / ImmersionConstants.WINDOW_ASPECT_RATIO_9_16;
        X = -(videoWidth - windowWidth) / 2; //左右裁剪
        // 判断下tab是否沉浸
        isBottomTabImmersive = videoHeight + bottomTabHeight > windowHeight;
      }
      return {
        videoSize: {
          width: videoWidth,
          height: videoHeight,
        },
        videoPosition: {
          x: X,
          y: Y,
        },
        immersionSetting: {
          isStatusBarImmersive: isStatusBarImmersive,
          isBottomTabImmersive: isBottomTabImmersive,
        },
      } as ImmersionInfo;
    },
  },
  /**
   * 6
   * rule: 视频比例：9/16、窗口宽：[0, Infinity]、窗口比例：[0, 9 / 20)
   * func: "高度：窗口宽 * (17.8 / 9) | 宽度：窗口宽 | 状态栏：不沉浸 | 底部tab：不沉浸"
   */
  {
    videoRatio: ImmersionConstants.VIDEO_ASPECT_RATIO_9_16,
    windowWidthRange: [0, Infinity],
    windowRatioRange: [0, ImmersionConstants.WINDOW_ASPECT_RATIO_9_20],
    immersionCalculationFunc: (videoSize: Size, windowSize: Size, bottomTabHeight: number, statusBarHeight: number): ImmersionInfo => {
      const windowWidth = windowSize.width;
      const windowHeight = windowSize.height;
      const restShowAreaHeight = windowHeight - bottomTabHeight - statusBarHeight; // 剩余区域的高
      const videoWidth = windowWidth * ImmersionConstants.VIDEO_STRETCH_ASPECT_RATIO_17o8_16;
      const videoHeight = videoWidth / ImmersionConstants.WINDOW_ASPECT_RATIO_9_16;
      return {
        videoSize: {
          width: videoWidth,
          height: videoHeight,
        },
        videoPosition: {
          x: -(videoWidth - windowWidth) / 2,
          y: statusBarHeight + (restShowAreaHeight - videoHeight) / 2,
        },
        immersionSetting: {
          isStatusBarImmersive: false,
          isBottomTabImmersive: false,
        },
      } as ImmersionInfo;
    },
  },
];

/**
 * 非9:16的视频： 默认计算规则：减去上下区域之后在剩余区域(窗口减去状态栏和下tab栏剩余的部分)居中
 */
export const DEFAULT_IMMERSION_CALCULATION_FUNC = (videoSize: Size, windowSize: Size, bottomTabHeight: number, statusBarHeight: number): ImmersionInfo => {
  // 视频比例
  const videoRatio = videoSize.width / videoSize.height;
  const windowWidth = windowSize.width;
  const windowHeight = windowSize.height;

  // 根据窗口大小和视频大小自适应缩放至撑满宽或高，减去状态栏和底部tab后上居中
  const restShowAreaHeight = windowHeight - statusBarHeight - bottomTabHeight; // 剩余区域的高
  const restShowAreaWidth = windowWidth; // 剩余区域的宽
  const restShowAreaRatio = restShowAreaWidth / restShowAreaHeight; // 剩余区域比例

  let videoHeight: number;
  let videoWidth: number;
  let X = 0;
  let Y = 0;

  // 判断视频比例与剩余区域比例的关系
  if (restShowAreaRatio >= videoRatio) {
    // 竖向视频，高撑满
    videoHeight = windowHeight - bottomTabHeight - statusBarHeight; // 窗口高 - 底部tab高度 - 状态栏高度
    videoWidth = videoHeight * videoRatio;
    Y = statusBarHeight;
    X = (windowWidth - videoWidth) / 2;
  } else {
    // 横向视频，宽撑满，在rest区域居中
    videoWidth = windowWidth;
    videoHeight = videoWidth / videoRatio;
    Y = statusBarHeight + (restShowAreaHeight - videoHeight) / 2; // 居中
  }

  return {
    videoSize: {
      width: videoWidth,
      height: videoHeight,
    },
    videoPosition: {
      x: X,
      y: Y,
    },
    immersionSetting: {
      isStatusBarImmersive: false,
      isBottomTabImmersive: false,
    },
  } as ImmersionInfo;
};

/**
 * 常规状态下全沉浸时的沉浸式计算规则
 * @param windowSize 窗口尺寸
 * @returns
 */
function commonFullImmersionCalculationFunc(windowSize: Size): ImmersionInfo {
  const videoHeight = windowSize.height;
  const videoWidth = videoHeight * ImmersionConstants.WINDOW_ASPECT_RATIO_9_16;
  return {
    videoSize: {
      width: videoWidth,
      height: videoHeight,
    },
    videoPosition: {
      x: (windowSize.width - videoWidth) / 2,
      y: 0,
    },
    immersionSetting: {
      isStatusBarImmersive: true,
      isBottomTabImmersive: true,
    },
  } as ImmersionInfo;
}
